export const createPallete = (palette) => {
  const colors = palette.split('_')
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  const res = []

  colors.forEach((c) => {
    ctx.fillStyle = c
    ctx.clearRect(0, 0, 1, 1)
    ctx.fillRect(0, 0, 1, 1)

    const imageData = ctx.getImageData(0, 0, 1, 1)

    res.push([imageData.data[0], imageData.data[1], imageData.data[2]])
  })

  return res
}
export function ditheringFilter(imageData, palette) {
  if (!palette) {
    palette = [
      { r: 255, g: 255, b: 255 },
      { r: 0, g: 0, b: 0 }
    ]
  } else {
    palette = createPallete(palette)
  }
  const w = imageData.width
  const h = imageData.height
  const data = imageData.data

  for (let i = 0; i < data.length; i += 4) {
    const r = data[i]
    const g = data[i + 1]
    const b = data[i + 2]
    const c = getClosestColor({ r, g, b }, palette)

    data[i] = c.r
    data[i + 1] = c.g
    data[i + 2] = c.b

    const delta = sub({ r, g, b }, c)
    const x = (i / 4) % w
    const y = Math.floor(i / 4 / w)

    if (x + 1 < w) refresh(data, i + 4, mul(delta, 7 / 16))
    if (x - 1 > 0 && y + 1 < h) { refresh(data, i + 4 * w - 4, mul(delta, 3 / 16)) }
    if (y + 1 < h) refresh(data, i + 4 * w, mul(delta, 5 / 16))
    if (x + 1 < w && y + 1 < h) { refresh(data, i + 4 * w + 4, mul(delta, 1 / 16)) }
  }

  return imageData
}

export function getClosestColor(currentColor, colorPalette) {
  let closestColor = null
  let minDistance = Number.MAX_VALUE

  for (const color of colorPalette) {
    const distance = Math.sqrt(
      Math.pow(color[0] - currentColor[0], 2) +
      Math.pow(color[1] - currentColor[1], 2) +
      Math.pow(color[2] - currentColor[2], 2)
    )

    if (distance < minDistance) {
      minDistance = distance
      closestColor = color
    }
  }

  return closestColor
}

function refresh(data, i, dc) {
  data[i] += dc.r
  data[i + 1] += dc.g
  data[i + 2] += dc.b
}

function sub(c1, c2) {
  return {
    r: c1.r - c2.r,
    g: c1.g - c2.g,
    b: c1.b - c2.b
  }
}

function mul(c, k) {
  return {
    r: c.r * k,
    g: c.g * k,
    b: c.b * k
  }
}
// 定义Burke抖动算法
export function ditheringBurke(imageData) {
  const width = imageData.width
  const height = imageData.height
  const data = imageData.data
  // 定义抖动矩阵
  const matrix = [
    [0, 0, 0, 8, 4],
    [2, 4, 8, 4, 2],
    [1, 2, 4, 2, 1]
  ]
  // 遍历图像像素
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const index = (y * width + x) * 4
      const oldR = data[index]
      const oldG = data[index + 1]
      const oldB = data[index + 2]
      const newR = oldR > 127 ? 255 : 0
      const newG = oldG > 127 ? 255 : 0
      const newB = oldB > 127 ? 255 : 0
      const errR = oldR - newR
      const errG = oldG - newG
      const errB = oldB - newB
      // 更新当前像素
      data[index] = newR
      data[index + 1] = newG
      data[index + 2] = newB
      // 传播误差到相邻像素
      for (let i = 0; i < matrix.length; i++) {
        for (let j = 0; j < matrix[i].length; j++) {
          const offsetX = j - Math.floor(matrix[i].length / 2)
          const offsetY = i
          const neighborX = x + offsetX
          const neighborY = y + offsetY
          if (neighborX >= 0 && neighborX < width && neighborY >= 0 && neighborY < height) {
            const neighborIndex = (neighborY * width + neighborX) * 4
            data[neighborIndex] += errR * matrix[i][j] / 32
            data[neighborIndex + 1] += errG * matrix[i][j] / 32
            data[neighborIndex + 2] += errB * matrix[i][j] / 32
          }
        }
      }
    }
  }
  return imageData
}
